﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SPM.DAL;
using SPM.DTL;

namespace SPM.BL
{
    public abstract class BusinessObject<TDto>
        where TDto: class, IDataTransferObject, new()
    {
        private const int EmptyId = -1;

        /// <summary>
        /// Cria um objeto DTO.
        /// </summary>
        /// <returns>
        /// Um novo objeto DTO, devidamente inicializado
        /// </returns>
        public TDto CreateDto()
        {
            TDto dto = new TDto();
            dto.Id = EmptyId;
            return dto;
        }

        protected bool IsNew(TDto dto)
        {
            return dto.Id == EmptyId;
        }

        protected DataAccessObject<TDto> dao;

        protected DataAccessObject<TDto> Dao
        {
            get
            {
                if (dao == null)
                    dao = CreateDao();

                return dao;
            }
        }

        protected abstract DataAccessObject<TDto> CreateDao();

        /// <summary>
        /// Pega todos os DTOs.
        /// </summary>
        /// <returns>
        /// Uma lista com todos os DTOs;
        /// </returns>
        public IList<TDto> GetAll()
        {
            return Dao.GetAll();
        }

        /// <summary>
        /// Salva os dados de um DTO na tabela
        /// </summary>
        /// <param name="dto">
        /// Dados a serem salvos
        /// </param>
        /// <remarks>
        /// Para que esse método funcione corretamente, é necessário
        /// que o id dos DTOs nunca seja alterado pela UI. Caso isso
        /// seja possível, uma implementação diferente seria necessária...
        /// </remarks>
        /// <returns>
        /// Retorna um inteiro com o valor do último id inserido ou o 
        /// id do registro atualizado e -1 caso o dto que se está tentado
        /// inserir não seja válido
        /// </returns>
        public int Save(TDto dto)
        {
            if (Validate(dto))
            {
                if (IsNew(dto))
                {
                    Dao.AddItem(dto);
                    return dao.GetLastIdentity();
                }
                else
                {
                    Dao.UpdateItem(dto.Id, dto);
                    return dto.Id;
                }
            }
            return -1;
        }
		
        public void Delete(int id)
        {
            Dao.DeleteItem(id);
        }

        /// <summary>
        /// Valida os dados do DTO antes que eles
        /// sejam gravados.
        /// </summary>
        /// <param name="dto">
        /// DTO a ser validado.
        /// </param>
        /// <returns>
        /// <c>true</c> se o DTO é válido,
        /// <c>false</c> em caso contrário.
        /// </returns>
        protected abstract bool Validate(TDto dto);

        public TDto GetById(int id)
        {
            if (id > 0)
            {
                return Dao.GetItem(id);
            }
            else
            {
                throw new ArgumentException("O valor de id deve ser superior a 0 (zero).");
            }
        }

        //Não sei se este método é realmente necessário na camada BL.
        //Neste momento apenas o estou usando nos testes.
        public int GetLastIdentity()
        {
            return dao.GetLastIdentity();
        }
    }
}
